﻿using Castle.DynamicProxy;
using Shake.Domain.Infrastructures;
using Shake.Framework.Attributes;
using Shake.Framework.Models;
using Shake.Framework.Services;
using Shake.Framework.Setup;
using System.Linq;
using System.Text;

namespace Shake.Framework.Interceptors
{
    public class CacheInterceptor : IInterceptor
    {
        private IShakeCacheManager<object> _shakeCacheManger;
        public CacheInterceptor()
        {
            _shakeCacheManger = AutofacConfig.Resolve<IShakeCacheManager<object>>();
        }

        public void Intercept(IInvocation invocation)
        {
            var shakeCacheAttributes = invocation.Method.GetCustomAttributes(typeof(ShakeCacheAttribute), false).OfType<ShakeCacheAttribute>().ToList();
            if (shakeCacheAttributes.Count == 0)
            {
                invocation.Proceed(); // 没指定缓存
                return;
            }

            var key = BuildKey(invocation);
            if (string.IsNullOrEmpty(key))
            {
                invocation.Proceed();
                return;
            }

            var cacheValue = _shakeCacheManger.Get(key);
            if (cacheValue == null)
            {
                invocation.Proceed();
                _shakeCacheManger.Put(key, invocation.ReturnValue);
                return;
            }
            invocation.ReturnValue = cacheValue;
        }

        private string BuildKey(IInvocation invocation)
        {
            var result = new StringBuilder();
            result.Append(invocation.Method.DeclaringType.FullName);

            var parameters = invocation.Method.GetParameters().ToList();
            if (parameters.Count == 0) return result.ToString();

            for (int i = 0; i < parameters.Count; i++)
            {
                var parameterInfo = parameters[i];
                var parameterType = parameterInfo.ParameterType;
                string value;
                if (parameterType.IsValueType)
                {
                    var argumentValue = invocation.GetArgumentValue(i);
                    value = string.Format(":{0}", argumentValue.GetHashCode());
                }
                else if (parameterType == typeof(string))
                {
                    var argumentValue = invocation.GetArgumentValue(i);
                    value = string.Format(":{0}", argumentValue);
                }
                else if (parameterType.GetInterface(typeof(IFilter).Name) != null || parameterType == typeof(PageArgument))
                {
                    var argumentValue = invocation.GetArgumentValue(i);
                    value = GetPropertyValues(argumentValue);
                }
                else
                {
                    return null; // 如果包含其他类型参数，则不可以缓存
                }
                result.Append(value);
            }

            return result.ToString();
        }

        private string GetPropertyValues(object filter)
        {
            if (filter == null) return string.Empty;
            var result = new StringBuilder();
            var properties = filter.GetType().GetProperties();
            foreach (var property in properties)
            {
                var value = property.GetValue(filter);
                if (value == null) continue;

                var hashCode = string.Format(":{0}", value.GetHashCode());
                result.Append(hashCode);
            }
            return result.ToString();
        }
    }
}
